#include "LTree.h"
#include "RotationNode.h"
#include "ScaleNode.h"
#include "GeomNode.h"
#include "TranslateNode.h"
#include "GeomBuilder.h"
#include "TreeBuilder.h"

LTree::LTree(LGrammar *gr,
			 float deg = 30,
			 Location l = Location(0.0, 0.0, 0.0),
			 int dep = 5)	:
		curDepth(1.0),
		degree(deg),
		loc(l),
		depth(dep),
		generated(false),
		pattern("") {
	root = new SceneRoot();
	grammar = gr;
	currentNode = new TranslateNode(loc);
	root->AddChild(currentNode);
}

LTree::LTree(LTree const &rhs) :
		pattern(rhs.pattern),
		loc(rhs.loc),
		depth(rhs.depth),
		generated(rhs.generated),
		degree(rhs.degree),
		curDepth(rhs.curDepth) {
	grammar = rhs.grammar;
	//set it to root's first child, because either a) the only child is the
	//translate node, or the tree has already been generated and currentNode is
	//unnecessary.
	if(rhs.generated) {
		root = new SceneRoot(*rhs.root);
		currentNode = root;
	} else {
		root = new SceneRoot();
		currentNode = new TranslateNode(loc);
		root->AddChild(currentNode);
	}

}

LTree& LTree::operator=(LTree const &rhs) {
	pattern = rhs.pattern;
	loc = rhs.loc;
	depth = rhs.depth;
	generated = rhs.generated;
	degree = rhs.degree;
	curDepth = rhs.curDepth;
	grammar = rhs.grammar;

	delete root;
	if(rhs.generated) {
		root = new SceneRoot(*rhs.root);
		currentNode = root;
	} else {
		root = new SceneRoot();
		currentNode = new TranslateNode(loc);
		root->AddChild(currentNode);
	}
	return *this;
}

LTree::~LTree(void) {
	delete root;
}

SceneRoot* LTree::getDrawables(void) {
	if(!generated) {
		grammar->reset();
		generateTree();
		generated = true;
	}
	return root;
}

void LTree::update(void) {

}

int LTree::getSize(void) {
	return 1;
}

Location LTree::getLocation(void) {
	return loc;
}

bool LTree::draw(void) {
	return visible;
}

void LTree::setDraw(bool d) {
	visible = d;
}

bool LTree::canSplit(void) {
	return false;
}

std::list<WorldObject *> LTree::split(void) {
	return std::list<WorldObject *>();
}

bool LTree::deleteMe(void) {
	return deleteThis;
}

void LTree::setDelete(bool d) {
	deleteThis = d;
}

void LTree::pushNode(void) {
	curDepth *= .75;
	nodeStack.push(currentNode);
}

void LTree::popNode(void) {
	curDepth /= .75;
	currentNode = nodeStack.top();
	nodeStack.pop();
}

void LTree::rotateAlpha(float degree) {
	RotationNode *newNode = new RotationNode(new D3DXVECTOR3(0.0, 0.0, 1.0), degree );
	currentNode->AddChild(newNode);
	currentNode = newNode;
}

void LTree::rotateTheta(float degree) {
	RotationNode *newNode = new RotationNode(new D3DXVECTOR3(0.0, 1.0, 0.0), degree );
	currentNode->AddChild(newNode);
	currentNode = newNode;
}

void LTree::addLeaf(void) {
	static GeomNode *leafNode = 0;
	if(leafNode == 0) {
		leafNode = BuildSphere(1.0, 4, 4);
		leafNode->SetMaterial(0.00, 5.0, 0.0);
	}

	SceneNode* newNode = new ScaleNode(4.0 * curDepth, 4.0 * curDepth, 4.0 * curDepth);
	newNode->AddChild(leafNode);
	currentNode->AddChild(newNode);

	newNode = new TranslateNode(0.0, curDepth * 4.0, 0.0);
	currentNode->AddChild(newNode);
	currentNode = newNode;
}

void LTree::addPetal(void) {
	static GeomNode *petalNode = 0;
	if(petalNode == 0) {
		petalNode = BuildTri(Vect3D(0.0, 0.0, 0.0), Vect3D(-1.0, 1.0, 0.0), Vect3D(1.0, 1.0, 0.0));
		petalNode->SetMaterial(0.0, 1.0, 0.0);
	}

	SceneNode* newNode = new ScaleNode(3.0 * curDepth, 6.0 * curDepth, 3.0 * curDepth);
	newNode->AddChild(petalNode);
	currentNode->AddChild(newNode);
}

void LTree::addBranch(void) {
	static GeomNode *branchNode = 0;
	if(branchNode == 0) {
		branchNode = BuildCylinder(1.0, 1.0, 5);
		branchNode->SetMaterial(1.0, 0.7, 0.0);
	}
	SceneNode* newNode = new ScaleNode(0.6 * curDepth, 4.0 * curDepth, 0.6 * curDepth);
//	node = BuildCylinder(.6*curDepth, curDepth * 4.0, 6);
//	node->SetMaterial(1.0, 0.7, 0.0);
	newNode->AddChild(branchNode);
	currentNode->AddChild(newNode);

	newNode = new TranslateNode(0.0, curDepth * 4.0, 0.0);
	currentNode->AddChild(newNode);
	currentNode = newNode;
}

std::string LTree::toString(void) {
	if(!generated) {
		generateTree();
		generated = true;
	}
	return pattern;
}

void LTree::generateTree(void) {
	if(generated) {
		return;
	}
	grammar->setDepth(depth);
	grammar->reset();

	while(true) {
		char nextChar = grammar->getNextChar();
		pattern += nextChar;
		switch(nextChar) {
		//switch(grammar->getNextChar()) {
			//Push the stack.
			case '[':
				pushNode();
				break;
			//Pop the stack.
			case ']':
				popNode();
				break;
			//Rotate degree degrees around the z-axis.
			case '+':
				rotateAlpha(degree * 3.14 / 180.0);
				break;
			//Rotate -degree degrees around the z-axis.
			case '-':
				rotateAlpha(-degree * 3.14 / 180.0);
				break;
			//Rotate degree degrees around the y-axis.
			case '*':
				rotateTheta(degree * 3.14 / 180.0);
				break;
			//Rotate -degree degrees around the y -axis.
			case '/':
				rotateTheta(-degree * 3.14 / 180.0);
				break;
			//Draw a leaves (green sphere)
			case 'L':
			//	newNode = new ScaleNode(0.8 * curDepth, curDepth, 0.8 * curDepth);
				addLeaf();
				break;
			//Draw a petal (green triangles)
			case 'P':
				addPetal();
				break;
			//Exit - we are done!
			case 0:
				return;
			//Otherwise draw a branch/stem/trunk/etc.
			default:
				addBranch();
				break;
		}
	}
	generated = true;

}


/*#pragma deprecated
//getTree and getTestTree have been merged into TreeBuilder::getTrees, and TreeBuilder::createTree().
LTree *getTree(float x, float y, float z) {
	static int test = 0;
	LGrammar *grammar = new LGrammar();

	LTree *ltree = new LTree(grammar,
		andom() % 35 + 15,
//		30,
		Location((float) (rand() % 50 + x), (float) (rand() % 50 + y), (float) (rand() % 50) + z),
		rand() % 5 + 8);
//		5);

	grammar->setStartString("T");

//	grammar->addRule(new LGrammarRule('T', "TT**-[-T+T+T]*+[T-T-T]"));
//	grammar->addRule(new LGrammarRule('T', "T[+T][**-T][/-T][L]"));
	
	
	LGrammarRule *tree = new LGrammarRule('T', "cB");
	LGrammarRule *segment = new LGrammarRule('S', "McB[L]", 3);
//		segment->addProductionRule("MLS", 2);
//		segment->addProductionRule("B",1);
	LGrammarRule *branches = new LGrammarRule('B', "bB", 3);
		branches->addProductionRule("b", 1);
	LGrammarRule *branch = new LGrammarRule('b', "[S]", 1);
	LGrammarRule *modifiers = new LGrammarRule('M', "YZ");
	LGrammarRule *ymods = new LGrammarRule('Y', "Yy", 2);
		ymods->addProductionRule("y", 1);
	LGrammarRule *ymod = new LGrammarRule('y', "*", 1);
		ymod->addProductionRule("/",1);
	LGrammarRule *zmods = new LGrammarRule('Z', "z", 2);
	//	zmods->addProductionRule("z", 1);
	LGrammarRule *zmod = new LGrammarRule('z', "+", 1);
		zmod->addProductionRule("-",1);

	grammar->addRule(tree);
	grammar->addRule(segment);
	grammar->addRule(branches);
	grammar->addRule(branch);
	grammar->addRule(modifiers);
	grammar->addRule(ymods);
	grammar->addRule(ymod);
	grammar->addRule(zmods);
	grammar->addRule(zmod);

	return ltree;
}

#pragma deprecated
SceneRoot* getTestTree(float x, float y, float z) {
	
//	grammar->setStartString("X");
//	grammar->addRule(new LGrammarRule('X', "X[+X][**-X][/-X][L]"));
	

	//LGrammarRule *rule = new LGrammarRule('F', "FF");
	//grammar->addRule(rule);
	//rule = new LGrammarRule('P', "*P", 1);
	//rule->addProductionRule("+", 1);
	//rule = new LGrammarRule('N', "/N", 1);
	//rule->addProductionRule("-", 1);
	//grammar->addRule(new LGrammarRule('X', "F[+X][-X]FL"));
	LTree *tree = getTree(x, y, z);
	return tree->getDrawables();

}
*/